/*
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at 
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  
 */

using System;
using java = biz.ritter.javapi;
using org.apache.commons.collections.comparators;

namespace org.apache.commons.collections
{

    /**
     * Provides convenient static utility methods for <Code>Comparator</Code>
     * objects.
     * <p>
     * Most of the functionality in this class can also be found in the 
     * <code>comparators</code> package. This class merely provides a 
     * convenient central place if you have use for more than one class
     * in the <code>comparators</code> subpackage.
     *
     * @since Commons Collections 2.1
     * @version $Revision: 7130 $ $Date: 2011-06-04 20:48:14 +0200 (Sa, 04. Jun 2011) $
     * 
     * @author Paul Jack
     * @author Stephen Colebourne
     */
    public class ComparatorUtils
    {

        /**
         * ComparatorUtils should not normally be instantiated.
         */
        public ComparatorUtils()
        {
        }

        /**
         * Comparator for natural sort order.
         *
         * @see ComparableComparator#getInstance
         */
        public static readonly java.util.Comparator<Object> NATURAL_COMPARATOR = ComparableComparator.getInstance();

        /**
         * Gets a comparator that uses the natural order of the objects.
         *
         * @return  a comparator which uses natural order
         */
        public static java.util.Comparator<Object> naturalComparator()
        {
            return NATURAL_COMPARATOR;
        }

        /**
         * Gets a comparator that compares using two {@link Comparator}s.
         * <p>
         * The second comparator is used if the first comparator returns equal.
         *
         * @param comparator1  the first comparator to use, not null
         * @param comparator2  the first comparator to use, not null
         * @return a {@link ComparatorChain} formed from the two comparators
         * @throws NullPointerException if either comparator is null
         * @see ComparatorChain
         */
        public static java.util.Comparator<Object> chainedComparator(java.util.Comparator<Object> comparator1, java.util.Comparator<Object> comparator2)
        {
            return chainedComparator(new java.util.Comparator<Object>[] { comparator1, comparator2 });
        }

        /**
         * Gets a comparator that compares using an array of {@link Comparator}s, applied
         * in sequence until one returns not equal or the array is exhausted.
         *
         * @param comparators  the comparators to use, not null or empty or containing nulls
         * @return a {@link ComparatorChain} formed from the input comparators
         * @throws NullPointerException if comparators array is null or contains a null
         * @see ComparatorChain
         */
        public static java.util.Comparator<Object> chainedComparator(java.util.Comparator<Object>[] comparators)
        {
            ComparatorChain chain = new ComparatorChain();
            for (int i = 0; i < comparators.Length; i++)
            {
                if (comparators[i] == null)
                {
                    throw new java.lang.NullPointerException("Comparator cannot be null");
                }
                chain.addComparator(comparators[i]);
            }
            return chain;
        }

        /**
         * Gets a comparator that compares using a collection of {@link Comparator}s,
         * applied in (default iterator) sequence until one returns not equal or the 
         * collection is exhausted.
         *
         * @param comparators  the comparators to use, not null or empty or containing nulls
         * @return a {@link ComparatorChain} formed from the input comparators
         * @throws NullPointerException if comparators collection is null or contains a null
         * @throws ClassCastException if the comparators collection contains the wrong object type
         * @see ComparatorChain
         */
        public static java.util.Comparator<Object> chainedComparator(java.util.Collection<Object> comparators)
        {
            return chainedComparator(
                (java.util.Comparator<Object>[])comparators.toArray(new java.util.Comparator<Object>[comparators.size()])
            );
        }

        /**
         * Gets a comparator that reverses the order of the given comparator.
         *
         * @param comparator  the comparator to reverse
         * @return  a comparator that reverses the order of the input comparator
         * @see ReverseComparator
         */
        public static java.util.Comparator<Object> reversedComparator(java.util.Comparator<Object> comparator)
        {
            if (comparator == null)
            {
                comparator = NATURAL_COMPARATOR;
            }
            return new ReverseComparator(comparator);
        }

        /**
         * Gets a Comparator that can sort bool objects.
         * <p>
         * The parameter specifies whether true or false is sorted first.
         * <p>
         * The comparator throws NullPointerException if a null value is compared.
         * 
         * @param trueFirst  when <code>true</code>, sort 
         *        <code>true</code> {@link Boolean}s before
         *        <code>false</code> {@link Boolean}s.
         * @return  a comparator that sorts booleans
         */
        public static java.util.Comparator<Object> booleanComparator(bool trueFirst)
        {
            return BooleanComparator.getBooleanComparator(trueFirst);
        }

        /**
         * Gets a Comparator that controls the comparison of <code>null</code> values.
         * <p>
         * The returned comparator will consider a null value to be less than
         * any nonnull value, and equal to any other null value.  Two nonnull
         * values will be evaluated with the given comparator.
         *
         * @param comparator the comparator that wants to allow nulls
         * @return  a version of that comparator that allows nulls
         * @see NullComparator
         */
        public static java.util.Comparator<Object> nullLowComparator(java.util.Comparator<Object> comparator)
        {
            if (comparator == null)
            {
                comparator = NATURAL_COMPARATOR;
            }
            return new NullComparator(comparator, false);
        }

        /**
         * Gets a Comparator that controls the comparison of <code>null</code> values.
         * <p>
         * The returned comparator will consider a null value to be greater than
         * any nonnull value, and equal to any other null value.  Two nonnull
         * values will be evaluated with the given comparator.
         *
         * @param comparator the comparator that wants to allow nulls
         * @return  a version of that comparator that allows nulls
         * @see NullComparator
         */
        public static java.util.Comparator<Object> nullHighComparator(java.util.Comparator<Object> comparator)
        {
            if (comparator == null)
            {
                comparator = NATURAL_COMPARATOR;
            }
            return new NullComparator(comparator, true);
        }

        /**
         * Gets a Comparator that passes transformed objects to the given comparator.
         * <p>
         * Objects passed to the returned comparator will first be transformed
         * by the given transformer before they are compared by the given
         * comparator.
         *
         * @param comparator  the sort order to use
         * @param transformer  the transformer to use
         * @return  a comparator that transforms its input objects before comparing them
         * @see  TransformingComparator
         */
        public static java.util.Comparator<Object> transformedComparator(java.util.Comparator<Object> comparator, Transformer transformer)
        {
            if (comparator == null)
            {
                comparator = NATURAL_COMPARATOR;
            }
            return new TransformingComparator(transformer, comparator);
        }

        /**
         *  Returns the smaller of the given objects according to the given 
         *  comparator, returning the second object if the comparator
         *  returns equal.
         * 
         *  @param o1  the first object to compare
         *  @param o2  the second object to compare
         *  @param comparator  the sort order to use
         *  @return  the smaller of the two objects
         */
        public static Object min(Object o1, Object o2, java.util.Comparator<Object> comparator)
        {
            if (comparator == null)
            {
                comparator = NATURAL_COMPARATOR;
            }
            int c = comparator.compare(o1, o2);
            return (c < 0) ? o1 : o2;
        }

        /**
         *  Returns the larger of the given objects according to the given 
         *  comparator, returning the second object if the comparator 
         *  returns equal.
         * 
         *  @param o1  the first object to compare
         *  @param o2  the second object to compare
         *  @param comparator  the sort order to use
         *  @return  the larger of the two objects
         */
        public static Object max(Object o1, Object o2, java.util.Comparator<Object> comparator)
        {
            if (comparator == null)
            {
                comparator = NATURAL_COMPARATOR;
            }
            int c = comparator.compare(o1, o2);
            return (c > 0) ? o1 : o2;
        }

    }
}